package com;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import com.netflix.config.ConfigurationManager;
import com.netflix.hystrix.HystrixCollapser;
import com.netflix.hystrix.HystrixCollapser.CollapsedRequest;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;


class OrderDetail{
	private String orderId;
	private String orderOwner;
	public String getOrderId() {
		return orderId;
	}
	public void setOrderId(String orderId) {
		this.orderId = orderId;
	}
	public String getOrderOwner() {
		return orderOwner;
	}
	public void setOrderOwner(String orderOwner) {
		this.orderOwner = orderOwner;
	}
	
	public String toString() {		
		return "orderId: " + orderId + ", orderOwner: " + orderOwner ;
	}
}

//合并订单请求的处理器
class OrderHystrixCollapser extends
		HystrixCollapser<Map<String, OrderDetail>, OrderDetail, String> {

	String orderId;
	//在构造函数里传入请求参数
	public OrderHystrixCollapser(String orderId) {
		this.orderId = orderId;
	}
    //重写这个方法，以指定根据orderId去请求OrderDetail
	public String getRequestArgument() {
		return orderId;
	}
    //创建请求命令
	protected HystrixCommand<Map<String, OrderDetail>> createCommand(
			Collection<CollapsedRequest<OrderDetail, String>> requests) {
		return new MergerCommand(requests);
	}

	//把请求得到的结果和请求关联到一起
	protected void mapResponseToRequests(Map<String, OrderDetail> batchResponse,
			Collection<CollapsedRequest<OrderDetail, String>> requests) {
		for (CollapsedRequest<OrderDetail, String> request : requests) {
			// 请注意这里是得到单个请求的结果
			OrderDetail oneOrderDetail = batchResponse.get(request.getArgument());
			// 把结果关联到请求中
			request.setResponse(oneOrderDetail);
		}
	}
}

class MergerCommand extends HystrixCommand<Map<String, OrderDetail>> {

	//用orderDB模拟数据库中的数据
	static HashMap<String,String> orderDB = new HashMap<String,String> ();
	static 
	{
		orderDB.put("1","Peter");
		orderDB.put("2","Tom");
		orderDB.put("3","Mike");
	}
	
	Collection<CollapsedRequest<OrderDetail, String>> requests;

	public MergerCommand(
			Collection<CollapsedRequest<OrderDetail, String>> requests) {
		super(Setter.withGroupKey(HystrixCommandGroupKey.Factory
				.asKey("mergeDemo")));
		this.requests = requests;
	}

	//在run方法里根据请求参数返回结果
	protected Map<String, OrderDetail> run() throws Exception {
		List<String> orderIds = new ArrayList<String>();
		//通过for循环，整合参数
		for(CollapsedRequest<OrderDetail, String> request : requests) {
			orderIds.add(request.getArgument());
		}
		// 调用服务,根据多个订单Id获得多个订单对象
		Map<String, OrderDetail> ordersHM = getOrdersFromDB(orderIds);
		return ordersHM;
	}
	
	// 获得对象
	private Map<String, OrderDetail> getOrdersFromDB(List<String> orderIds) {
		Map<String, OrderDetail> result = new HashMap<String, OrderDetail>();
		for(String orderId : orderIds) {
			OrderDetail order = new OrderDetail();
			//这个本该是从数据库里得到，但为了模拟，仅从HashMap里取数据
			order.setOrderId(orderId);
			order.setOrderOwner(orderDB.get(orderId) );			
			result.put(orderId, order);
		}
		return result;
	}
}

public class HystrixMergeDemo{
	public static void main(String[] args){
		// 收集2秒内发生的请求，合并为一个命令执行
		ConfigurationManager.getConfigInstance().setProperty(
				"hystrix.collapser.default.timerDelayInMilliseconds", 2000);
		// 请求上下文
		HystrixRequestContext context = HystrixRequestContext
				.initializeContext();
		// 创建请求合并处理器
		OrderHystrixCollapser collapser1 = new OrderHystrixCollapser("1");
		OrderHystrixCollapser collapser2 = new OrderHystrixCollapser("2");
		OrderHystrixCollapser collapser3 = new OrderHystrixCollapser("3");
		
		// 异步执行
		Future<OrderDetail> future1 = collapser1.queue();
		Future<OrderDetail> future2 = collapser2.queue();
		Future<OrderDetail> future3 = collapser3.queue();
		
		try {
			System.out.println(future1.get());
			System.out.println(future2.get());
			System.out.println(future3.get());
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		
		context.shutdown();
	}
}
